const parser = require('@babel/parser');
const generator= require('@babel/generator').default
const traverse = require('@babel/traverse').default;
const types = require('@babel/types');  

const fs = require('fs');  

/**  
 * 保存path.node为json文件，命名为<type>.json  
 * @param {NodePath} path   
 */  
function saveAstNodeAsJson(path) {  
  console.log('path-->',path)
  const type = path.node.type;  
  fs.writeFileSync(`${type}.json`, JSON.stringify(path.node, null, 2), 'utf-8');  
  console.log(`已保存为 ${type}.json`);  
}
// 将 JavaScript 代码解析为 AST
const ast = parser.parse(`
    var a = 123;
    var b = -5;
    var c = String;
    var d = String.fromCharCode;

    function e()
    {
    var f = c(123),g = d(0x31);
        return a + b + f ;
    }

    while(true)
    {
        var h = 123;
        var i = 111;
        j = h + 456;
        i = i + 222;
    }
`);

function isExpressionConstant(PathOrNode)
{

    let node = PathOrNode.node || PathOrNode;

    let BrowList = ['window', 'document', 'navigator', 'location', 'history', 'screen',];

    if (types.isLiteral(node) && node.value != null)
    {
        return true;
    }

    if (types.isIdentifier(node) && BrowList.includes(node.name))
    {
        return true;
    }

    if (types.isIdentifier(node) && typeof globalThis[node.name] != "undefined") {
        return true;
    }

    if (types.isMemberExpression(node))
    {
        let {object,property} = node;

        if (types.isIdentifier(object) && typeof globalThis[object.name] != "undefined")
        {
            let properName = types.isIdentifier(property) ? property.name : property.value;
            if (typeof globalThis[object.name][properName] != "undefined") {
                return true;
            }
        }

        if (types.isMemberExpression(object))
        {
            return isExpressionConstant(object);
        }

    }

    if (types.isUnaryExpression(node) && ["+", "-", "!","typeof","~"].includes(node.operator)) {
        return isExpressionConstant(node.argument);
    }

    return false;
}

const restoreVarDeclarator =
{
    VariableDeclarator(path) {
        let scope = path.scope;
        let { id, init } = path.node;

        if (!types.isIdentifier(id) || init == null || !isExpressionConstant(init)) {
            return;
        }

        const binding = scope.getBinding(id.name);

        if (!binding) return;

        let { constant, referencePaths, constantViolations } = binding;  

        if (constantViolations.length > 1) {
            return;
        }

        if (constant || constantViolations[0] == path) {
            for (let referPath of referencePaths) {
                referPath.replaceWith(init);
            }
        }
    },
}

traverse(ast, restoreVarDeclarator);

// 将修改后的 AST 转换回 JavaScript 代码
const code =generator(ast).code;

console.log(code);

